home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / USER.PY < prev    next >
Encoding:
Python Source  |  2000-08-17  |  28.7 KB  |  867 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. """Access control package"""
  65.  
  66. __version__='$Revision: 1.110.4.5 $'[11:-2]
  67.  
  68. import Globals, socket, regex, SpecialUsers
  69. from Globals import HTMLFile, MessageDialog, Persistent, PersistentMapping
  70. from string import join,strip,split,lower
  71. from App.Management import Navigation, Tabs
  72. from Acquisition import Implicit
  73. from OFS.SimpleItem import Item
  74. from base64 import decodestring
  75. from App.ImageFile import ImageFile
  76. from Role import RoleManager
  77. from string import split, join, upper
  78. from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn
  79. from AuthEncoding import pw_validate
  80.  
  81. ListType=type([])
  82. NotImplemented='NotImplemented'
  83.  
  84. _marker=[]
  85.  
  86. class BasicUser(Implicit):
  87.     """Base class for all User objects"""
  88.  
  89.     # ----------------------------
  90.     # Public User object interface
  91.     # ----------------------------
  92.     
  93.     # Maybe allow access to unprotected attributes. Note that this is
  94.     # temporary to avoid exposing information but without breaking
  95.     # everyone's current code. In the future the security will be
  96.     # clamped down and permission-protected here. Because there are a
  97.     # fair number of user object types out there, this method denies
  98.     # access to names that are private parts of the standard User
  99.     # interface or implementation only. The other approach (only
  100.     # allowing access to public names in the User interface) would
  101.     # probably break a lot of other User implementations with extended
  102.     # functionality that we cant anticipate from the base scaffolding.
  103.     def __allow_access_to_unprotected_subobjects__(self, name, value=None):
  104.         deny_names=('name', '__', 'roles', 'domains', '_getPassword',
  105.                     'authenticate', '_shared_roles')
  106.         if name in deny_names:
  107.             return 0
  108.         return 1
  109.         
  110.     def __init__(self,name,password,roles,domains):
  111.         raise NotImplemented
  112.  
  113.     def getUserName(self):
  114.         """Return the username of a user"""
  115.         raise NotImplemented
  116.  
  117.     def getId(self):
  118.         """Get the ID of the user. The ID can be used, at least from
  119.         Python, to get the user from the user's
  120.         UserDatabase"""
  121.         return self.getUserName()        
  122.  
  123.     def _getPassword(self):
  124.         """Return the password of the user."""
  125.         raise NotImplemented
  126.  
  127.     def getRoles(self):
  128.         """Return the list of roles assigned to a user."""
  129.         raise NotImplemented
  130.  
  131.     def getRolesInContext(self, object):
  132.         """Return the list of roles assigned to the user,
  133.            including local roles assigned in context of
  134.            the passed in object."""
  135.         name=self.getUserName()
  136.         roles=self.getRoles()
  137.         local={}
  138.         object=getattr(object, 'aq_inner', object)
  139.         while 1:
  140.             if hasattr(object, '__ac_local_roles__'):
  141.                 local_roles=object.__ac_local_roles__
  142.                 if callable(local_roles):
  143.                     local_roles=local_roles()
  144.                 dict=local_roles or {}
  145.                 for r in dict.get(name, []):
  146.                     local[r]=1
  147.             if hasattr(object, 'aq_parent'):
  148.                 object=object.aq_parent
  149.                 continue
  150.             if hasattr(object, 'im_self'):
  151.                 object=object.im_self
  152.                 object=getattr(object, 'aq_inner', object)
  153.                 continue
  154.             break
  155.         roles=list(roles) + local.keys()
  156.         return roles
  157.  
  158.  
  159.     def getDomains(self):
  160.         """Return the list of domain restrictions for a user"""
  161.         raise NotImplemented
  162.  
  163.     # ------------------------------
  164.     # Internal User object interface
  165.     # ------------------------------
  166.     
  167.     def authenticate(self, password, request):
  168.         passwrd=self._getPassword()
  169.         result = pw_validate(passwrd, password)    
  170.         domains=self.getDomains()
  171.         if domains:
  172.             return result and domainSpecMatch(domains, request)
  173.         return result
  174.  
  175.     
  176.     def _shared_roles(self, parent):
  177.         r=[]
  178.         while 1:
  179.             if hasattr(parent,'__roles__'):
  180.                 roles=parent.__roles__
  181.                 if roles is None: return 'Anonymous',
  182.                 if 'Shared' in roles:
  183.                     roles=list(roles)
  184.                     roles.remove('Shared')
  185.                     r=r+roles
  186.                 else:
  187.                     try: return r+list(roles)
  188.                     except: return r
  189.             if hasattr(parent, 'aq_parent'):
  190.                 while hasattr(parent.aq_self,'aq_self'):
  191.                     parent=parent.aq_self
  192.                 parent=parent.aq_parent
  193.             else: return r
  194.  
  195.     def allowed(self, parent, roles=None):
  196.         """Check whether the user has access to parent, assuming that
  197.            parent.__roles__ is the given roles."""
  198.         if roles is None or 'Anonymous' in roles:
  199.             return 1
  200.         usr_roles=self.getRolesInContext(parent)
  201.         for role in roles:
  202.             if role in usr_roles:
  203.                 if (hasattr(self,'aq_parent') and
  204.                     hasattr(self.aq_parent,'aq_parent')):
  205.                     if parent is None: return 1
  206.                     if (not hasattr(parent, 'aq_inContextOf') and
  207.                         hasattr(parent, 'im_self')):
  208.                         # This is a method, grab it's self.
  209.                         parent=parent.im_self
  210.                     if not parent.aq_inContextOf(self.aq_parent.aq_parent,1):
  211.                         if 'Shared' in roles:
  212.                             # Damn, old role setting. Waaa
  213.                             roles=self._shared_roles(parent)
  214.                             if 'Anonymous' in roles: return 1
  215.                         return None
  216.                 return 1
  217.  
  218.         if 'Shared' in roles:
  219.             # Damn, old role setting. Waaa
  220.             roles=self._shared_roles(parent)
  221.             if roles is None or 'Anonymous' in roles: return 1
  222.             while 'Shared' in roles: roles.remove('Shared')
  223.             return self.allowed(parent,roles)
  224.  
  225.         return None
  226.  
  227.     hasRole=allowed
  228.     domains=[]
  229.     
  230.     def has_role(self, roles, object=None):
  231.         """Check to see if a user has a given role or roles."""
  232.         if type(roles)==type('s'):
  233.             roles=[roles]
  234.         if object is not None:
  235.             user_roles = self.getRolesInContext(object)
  236.         else:
  237.             # Global roles only...
  238.             user_roles=self.getRoles()
  239.         for role in roles:
  240.             if role in user_roles:
  241.                 return 1
  242.         return 0
  243.  
  244.     def has_permission(self, permission, object):
  245.         """Check to see if a user has a given permission on an object."""
  246.         roles=rolesForPermissionOn(permission, object)
  247.         return self.has_role(roles, object)
  248.  
  249.     def __len__(self): return 1
  250.     def __str__(self): return self.getUserName()
  251.     __repr__=__str__
  252.  
  253.  
  254. class SimpleUser(BasicUser):
  255.     """A very simple user implementation
  256.  
  257.     that doesn't make a database commitment"""
  258.  
  259.     def __init__(self,name,password,roles,domains):
  260.         self.name   =name
  261.         self.__     =password
  262.         self.roles  =roles
  263.         self.domains=domains
  264.  
  265.     def getUserName(self):
  266.         """Return the username of a user"""
  267.         return self.name
  268.  
  269.     def _getPassword(self):
  270.         """Return the password of the user."""
  271.         return self.__
  272.  
  273.     def getRoles(self):
  274.         """Return the list of roles assigned to a user."""
  275.         return tuple(self.roles)
  276.  
  277.     def getDomains(self):
  278.         """Return the list of domain restrictions for a user"""
  279.         return tuple(self.domains)
  280.  
  281. class SpecialUser(SimpleUser):
  282.     """Class for special users, like super and nobody"""
  283.     def getId(self): pass
  284.  
  285. class User(SimpleUser, Persistent):
  286.     """Standard User object"""
  287.  
  288. class Super(SpecialUser):
  289.     """Super user
  290.     """
  291.     def allowed(self,parent,roles=None):
  292.         return roles is not _what_not_even_god_should_do
  293.  
  294.     hasRole=allowed
  295.  
  296.     def has_role(self, roles, object=None): return 1
  297.  
  298.     def has_permission(self, permission, object): return 1
  299.  
  300. _remote_user_mode=0
  301. try:
  302.     f=open('%s/access' % INSTANCE_HOME, 'r')
  303. except IOError:
  304.     raise 'InstallError', (
  305.         'No access file found at %s - see INSTALL.txt' % INSTANCE_HOME
  306.         )
  307. try:
  308.     data=split(strip(f.readline()),':')
  309.     f.close()
  310.     _remote_user_mode=not data[1]
  311.     try:    ds=split(data[2], ' ')
  312.     except: ds=[]
  313.     super=Super(data[0],data[1],('manage',), ds)
  314.     del data
  315. except:
  316.     raise 'InstallError', 'Invalid format for access file - see INSTALL.txt'
  317.  
  318.  
  319. nobody=SpecialUser('Anonymous User','',('Anonymous',), [])
  320. system=Super('System Processes','',('manage',), [])
  321.  
  322. # stuff these in a handier place for importing
  323. SpecialUsers.nobody=nobody
  324. SpecialUsers.system=system
  325. SpecialUsers.super=super
  326.  
  327.  
  328. class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
  329.                       Item):
  330.     """Base class for UserFolder-like objects"""
  331.  
  332.     meta_type='User Folder'
  333.     id       ='acl_users'
  334.     title    ='User Folder'
  335.  
  336.     isPrincipiaFolderish=1
  337.     isAUserFolder=1
  338.  
  339.     manage_options=(
  340.         (
  341.         {'label':'Contents', 'action':'manage_main',
  342.          'help':('OFSP','User-Folder_Contents.stx')},
  343.         )
  344.         +RoleManager.manage_options
  345.         +Item.manage_options
  346.         )
  347.  
  348.     __ac_permissions__=(
  349.         ('Manage users',
  350.          ('manage_users','getUserNames','getUser','getUsers',
  351.           )
  352.          ),
  353.         )
  354.  
  355.  
  356.     # ----------------------------------
  357.     # Public UserFolder object interface
  358.     # ----------------------------------
  359.     
  360.     def getUserNames(self):
  361.         """Return a list of usernames"""
  362.         raise NotImplemented
  363.  
  364.     def getUsers(self):
  365.         """Return a list of user objects"""
  366.         raise NotImplemented
  367.  
  368.     def getUser(self, name):
  369.         """Return the named user object or None"""
  370.         raise NotImplemented
  371.  
  372.     def getUserById(self, id, default=_marker):
  373.         """Return the user corresponding to the given id.
  374.         """
  375.         try: return self.getUser(id)
  376.         except:
  377.            if default is _marker: raise
  378.            return default
  379.  
  380.     def _doAddUser(self, name, password, roles, domains):
  381.         """Create a new user"""
  382.         raise NotImplemented
  383.  
  384.     def _doChangeUser(self, name, password, roles, domains):
  385.         """Modify an existing user"""
  386.         raise NotImplemented
  387.  
  388.     def _doDelUsers(self, names):
  389.         """Delete one or more users"""
  390.         raise NotImplemented
  391.  
  392.  
  393.     # -----------------------------------
  394.     # Private UserFolder object interface
  395.     # -----------------------------------
  396.  
  397.  
  398.     _remote_user_mode=_remote_user_mode
  399.     _super=super
  400.     _nobody=nobody
  401.             
  402.     def validate(self,request,auth='',roles=None):
  403.  
  404.         if roles is _what_not_even_god_should_do:
  405.             request.response.notFoundError()
  406.         
  407.         parents=request.get('PARENTS', [])
  408.         if not parents:
  409.             parent=self.aq_parent
  410.         else: parent=parents[0]
  411.  
  412.         # If no authorization, only a user with a
  413.         # domain spec and no passwd or nobody can
  414.         # match
  415.         if not auth:
  416.             for ob in self.getUsers():
  417.                 domains=ob.getDomains()
  418.                 if domains:
  419.                     if ob.authenticate('', request):
  420.                         if ob.allowed(parent, roles):
  421.                             ob=ob.__of__(self)
  422.                             return ob
  423.             nobody=self._nobody
  424.             if self._isTop() and nobody.allowed(parent, roles):
  425.                 ob=nobody.__of__(self)
  426.                 return ob
  427.             return None
  428.  
  429.         # Only do basic authentication
  430.         if lower(auth[:6])!='basic ':
  431.             return None
  432.         name,password=tuple(split(decodestring(split(auth)[-1]), ':', 1))
  433.  
  434.         # Check for superuser
  435.         super=self._super
  436.         if self._isTop() and (name==super.getUserName()) and \
  437.         super.authenticate(password, request):
  438.             return super
  439.  
  440.         # Try to get user
  441.         user=self.getUser(name)
  442.         if user is None:
  443.  
  444.             # If the user was not found and we are the top level user
  445.             # database and the Anonymous user is allowed to access the
  446.             # requested object, return the Anonymous user.
  447.             if self._isTop() and self._nobody.allowed(parent, roles):
  448.                 user=self._nobody.__of__(self)
  449.                 return user
  450.  
  451.             # Otherwise, return None which will defer to higher level user
  452.             # databases or cause an unauthorized to be raised in the
  453.             # publisher layer.
  454.             return None
  455.  
  456.         # Try to authenticate the user
  457.         if not user.authenticate(password, request):
  458.  
  459.             # If no user was authenticated and we are the top level user
  460.             # database and the Anonymous user is allowed to access the
  461.             # requested object, return the Anonymous user.
  462.             if self._isTop() and self._nobody.allowed(parent, roles):
  463.                 user=self._nobody.__of__(self)
  464.                 return user
  465.  
  466.             # Otherwise, return None which will defer to higher level user
  467.             # databases or cause an unauthorized to be raised in the
  468.             # publisher layer.
  469.             return None
  470.  
  471.         # We need the user to be able to acquire!
  472.         user=user.__of__(self)
  473.  
  474.         # Try to authorize user
  475.         if user.allowed(parent, roles):
  476.             return user
  477.  
  478.         return None
  479.  
  480.  
  481.     if _remote_user_mode:
  482.         
  483.         def validate(self,request,auth='',roles=None):
  484.             parent=request['PARENTS'][0]
  485.             e=request.environ
  486.             if e.has_key('REMOTE_USER'):
  487.                 name=e['REMOTE_USER']
  488.             else:
  489.                 for ob in self.getUsers():
  490.                     domains=ob.getDomains()
  491.                     if domains:
  492.                         if ob.authenticate('', request):
  493.                             if ob.allowed(parent, roles):
  494.                                 ob=ob.__of__(self)
  495.                                 return ob
  496.                 nobody=self._nobody
  497.                 if self._isTop() and nobody.allowed(parent, roles):
  498.                     ob=nobody.__of__(self)
  499.                     return ob
  500.                 return None
  501.  
  502.             # Check for superuser
  503.             super=self._super
  504.             if self._isTop() and (name==super.getUserName()):
  505.                 return super
  506.  
  507.             # Try to get user
  508.             user=self.getUser(name)
  509.             if user is None:
  510.                 return None
  511.  
  512.             # We need the user to be able to acquire!
  513.             user=user.__of__(self)
  514.  
  515.             # Try to authorize user
  516.             if user.allowed(parent, roles):
  517.                 return user
  518.             return None
  519.  
  520.  
  521.     def _isTop(self):
  522.         try: return self.aq_parent.aq_base.isTopLevelPrincipiaApplicationObject
  523.         except: return 0
  524.  
  525.     def __len__(self):
  526.         return 1
  527.  
  528.     _mainUser=HTMLFile('mainUser', globals())
  529.     _add_User=HTMLFile('addUser', globals(),
  530.                        remote_user_mode__=_remote_user_mode)
  531.     _editUser=HTMLFile('editUser', globals(),
  532.                        remote_user_mode__=_remote_user_mode)
  533.     manage=manage_main=_mainUser
  534.  
  535.     def domainSpecValidate(self, spec):
  536.         for ob in spec:
  537.             sz=len(ob)
  538.             if not ((addr_match(ob) == sz) or (host_match(ob) == sz)):
  539.                 return 0
  540.         return 1
  541.  
  542.     def _addUser(self,name,password,confirm,roles,domains,REQUEST=None):
  543.         if not name:
  544.             return MessageDialog(
  545.                    title  ='Illegal value', 
  546.                    message='A username must be specified',
  547.                    action ='manage_main')
  548.         if not password or not confirm:
  549.             if not domains:
  550.                 return MessageDialog(
  551.                    title  ='Illegal value', 
  552.                    message='Password and confirmation must be specified',
  553.                    action ='manage_main')
  554.         if self.getUser(name) or (name==self._super.getUserName()):
  555.             return MessageDialog(
  556.                    title  ='Illegal value', 
  557.                    message='A user with the specified name already exists',
  558.                    action ='manage_main')
  559.         if (password or confirm) and (password != confirm):
  560.             return MessageDialog(
  561.                    title  ='Illegal value', 
  562.                    message='Password and confirmation do not match',
  563.                    action ='manage_main')
  564.         
  565.         if not roles: roles=[]
  566.         if not domains: domains=[]
  567.  
  568.         if domains and not self.domainSpecValidate(domains):
  569.             return MessageDialog(
  570.                    title  ='Illegal value', 
  571.                    message='Illegal domain specification',
  572.                    action ='manage_main')
  573.         self._doAddUser(name, password, roles, domains)        
  574.         if REQUEST: return self._mainUser(self, REQUEST)
  575.  
  576.  
  577.     def _changeUser(self,name,password,confirm,roles,domains,REQUEST=None):
  578.         if password == 'password' and confirm == 'confirm':
  579.             # Protocol for editUser.dtml to indicate unchanged password
  580.             password = confirm = None
  581.         if not name:
  582.             return MessageDialog(
  583.                    title  ='Illegal value', 
  584.                    message='A username must be specified',
  585.                    action ='manage_main')
  586.         if password == confirm == '':
  587.             if not domains:
  588.                 return MessageDialog(
  589.                    title  ='Illegal value', 
  590.                    message='Password and confirmation must be specified',
  591.                    action ='manage_main')
  592.         if not self.getUser(name):
  593.             return MessageDialog(
  594.                    title  ='Illegal value', 
  595.                    message='Unknown user',
  596.                    action ='manage_main')
  597.         if (password or confirm) and (password != confirm):
  598.             return MessageDialog(
  599.                    title  ='Illegal value', 
  600.                    message='Password and confirmation do not match',
  601.                    action ='manage_main')
  602.  
  603.         if not roles: roles=[]
  604.         if not domains: domains=[]
  605.  
  606.         if domains and not self.domainSpecValidate(domains):
  607.             return MessageDialog(
  608.                    title  ='Illegal value', 
  609.                    message='Illegal domain specification',
  610.                    action ='manage_main')
  611.         self._doChangeUser(name, password, roles, domains)
  612.         if REQUEST: return self._mainUser(self, REQUEST)
  613.  
  614.     def _delUsers(self,names,REQUEST=None):
  615.         if not names:
  616.             return MessageDialog(
  617.                    title  ='Illegal value', 
  618.                    message='No users specified',
  619.                    action ='manage_main')
  620.         self._doDelUsers(names)
  621.         if REQUEST: return self._mainUser(self, REQUEST)
  622.  
  623.     def manage_users(self,submit=None,REQUEST=None,RESPONSE=None):
  624.         """ """
  625.         if submit=='Add...':
  626.             return self._add_User(self, REQUEST)
  627.  
  628.         if submit=='Edit':
  629.             try:    user=self.getUser(reqattr(REQUEST, 'name'))
  630.             except: return MessageDialog(
  631.                     title  ='Illegal value',
  632.                     message='The specified user does not exist',
  633.                     action ='manage_main')
  634.             return self._editUser(self,REQUEST,user=user,password=user.__)
  635.  
  636.         if submit=='Add':
  637.             name    =reqattr(REQUEST, 'name')
  638.             password=reqattr(REQUEST, 'password')
  639.             confirm =reqattr(REQUEST, 'confirm')
  640.             roles   =reqattr(REQUEST, 'roles')
  641.             domains =reqattr(REQUEST, 'domains')
  642.             return self._addUser(name,password,confirm,roles,domains,REQUEST)
  643.  
  644.         if submit=='Change':
  645.             name    =reqattr(REQUEST, 'name')
  646.             password=reqattr(REQUEST, 'password')
  647.             confirm =reqattr(REQUEST, 'confirm')
  648.             roles   =reqattr(REQUEST, 'roles')
  649.             domains =reqattr(REQUEST, 'domains')
  650.             return self._changeUser(name,password,confirm,roles,
  651.                                     domains,REQUEST)
  652.  
  653.         if submit=='Delete':
  654.             names=reqattr(REQUEST, 'names')
  655.             return self._delUsers(names,REQUEST)
  656.  
  657.         return self._mainUser(self, REQUEST)
  658.  
  659.     def user_names(self):
  660.         return self.getUserNames()
  661.  
  662.     def manage_beforeDelete(self, item, container):
  663.         if item is self:
  664.             try: del container.__allow_groups__
  665.             except: pass
  666.  
  667.     def manage_afterAdd(self, item, container):
  668.         if item is self:
  669.             if hasattr(self, 'aq_base'): self=self.aq_base
  670.             container.__allow_groups__=self
  671.  
  672.     def __creatable_by_super__(self): return 1
  673.  
  674.     def _setId(self, id):
  675.         if id != self.id:
  676.             raise Globals.MessageDialog(
  677.                 title='Invalid Id',
  678.                 message='Cannot change the id of a UserFolder',
  679.                 action ='./manage_main',)
  680.  
  681.  
  682.  
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689. class UserFolder(BasicUserFolder):
  690.     """Standard UserFolder object
  691.  
  692.     A UserFolder holds User objects which contain information
  693.     about users including name, password domain, and roles.
  694.     UserFolders function chiefly to control access by authenticating
  695.     users and binding them to a collection of roles."""
  696.  
  697.     meta_type='User Folder'
  698.     id       ='acl_users'
  699.     title    ='User Folder'
  700.     icon     ='p_/UserFolder'
  701.  
  702.     def __init__(self):
  703.         self.data=PersistentMapping()
  704.  
  705.     def getUserNames(self):
  706.         """Return a list of usernames"""
  707.         names=self.data.keys()
  708.         names.sort()
  709.         return names
  710.  
  711.     def getUsers(self):
  712.         """Return a list of user objects"""
  713.         data=self.data
  714.         names=data.keys()
  715.         names.sort()
  716.         users=[]
  717.         f=users.append
  718.         for n in names:
  719.             f(data[n])
  720.         return users
  721.  
  722.     def getUser(self, name):
  723.         """Return the named user object or None"""
  724.         return self.data.get(name, None)
  725.  
  726.     def _doAddUser(self, name, password, roles, domains):
  727.         """Create a new user"""
  728.         self.data[name]=User(name,password,roles,domains)
  729.  
  730.     def _doChangeUser(self, name, password, roles, domains):
  731.         user=self.data[name]
  732.         if password is not None:
  733.             user.__=password
  734.         user.roles=roles
  735.         user.domains=domains
  736.  
  737.     def _doDelUsers(self, names):
  738.         for name in names:
  739.             del self.data[name]
  740.  
  741.  
  742. Globals.default__class_init__(UserFolder)
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749. def manage_addUserFolder(self,dtself=None,REQUEST=None,**ignored):
  750.     """ """
  751.     f=UserFolder()
  752.     self=self.this()
  753.     try:    self._setObject('acl_users', f)
  754.     except: return MessageDialog(
  755.                    title  ='Item Exists',
  756.                    message='This object already contains a User Folder',
  757.                    action ='%s/manage_main' % REQUEST['URL1'])
  758.     self.__allow_groups__=f
  759.     if REQUEST is not None:
  760.         REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
  761.  
  762.  
  763. def rolejoin(roles, other):
  764.     dict={}
  765.     for role in roles:
  766.         dict[role]=1
  767.     for role in other:
  768.         dict[role]=1
  769.     roles=dict.keys()
  770.     roles.sort()
  771.     return roles
  772.  
  773. addr_match=regex.compile('[0-9\.\*]*').match #TS
  774. host_match=regex.compile('[-A-Za-z0-9\.\*]*').match #TS
  775.  
  776.  
  777. def domainSpecMatch(spec, request):
  778.     host=''
  779.     addr=''
  780.  
  781.     if request.has_key('REMOTE_HOST'):
  782.         host=request['REMOTE_HOST']
  783.  
  784.     if request.has_key('REMOTE_ADDR'):
  785.         addr=request['REMOTE_ADDR']
  786.  
  787.     if not host and not addr:
  788.         return 0
  789.  
  790.     if not host:
  791.         try:    host=socket.gethostbyaddr(addr)[0]
  792.         except: pass
  793.     if not addr:
  794.         try:    addr=socket.gethostbyname(host)
  795.         except: pass
  796.  
  797.     _host=split(host, '.')
  798.     _addr=split(addr, '.')
  799.     _hlen=len(_host)
  800.     _alen=len(_addr)
  801.     
  802.     for ob in spec:
  803.         sz=len(ob)
  804.         _ob=split(ob, '.')
  805.         _sz=len(_ob)
  806.  
  807.         if addr_match(ob)==sz:
  808.             fail=0
  809.             for i in range(_sz):
  810.                 a=_addr[i]
  811.                 o=_ob[i]
  812.                 if (o != a) and (o != '*'):
  813.                     fail=1
  814.                     break
  815.             if fail:
  816.                 continue
  817.             return 1
  818.  
  819.         if host_match(ob)==sz:
  820.             if _hlen < _sz:
  821.                 continue
  822.             elif _hlen > _sz:
  823.                 _item=_host[-_sz:]
  824.             else:
  825.                 _item=_host
  826.             fail=0
  827.             for i in range(_sz):
  828.                 h=_item[i]
  829.                 o=_ob[i]
  830.                 if (o != h) and (o != '*'):
  831.                     fail=1
  832.                     break
  833.             if fail:
  834.                 continue
  835.             return 1
  836.     return 0
  837.  
  838.  
  839. def absattr(attr):
  840.     if callable(attr): return attr()
  841.     return attr
  842.  
  843. def reqattr(request, attr):
  844.     try:    return request[attr]
  845.     except: return None
  846.